package org.computumus.core.service.CodeService.impl;


import com.google.appengine.api.datastore.Key;
import com.google.appengine.api.datastore.KeyFactory;
import com.google.appengine.api.memcache.stdimpl.GCacheFactory;
import org.computumus.core.jdo.PMF;
import org.computumus.core.jdo.ScriptContainer;
import org.computumus.core.service.CodeService.Code;
import org.computumus.core.service.CodeService.CodeNotFoundException;
import org.computumus.core.service.CodeService.CodeService;
import org.computumus.core.session.Session;

import javax.cache.Cache;
import javax.cache.CacheException;
import javax.cache.CacheFactory;
import javax.cache.CacheManager;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Created by IntelliJ IDEA.
 * User: planadecu
 * Date: 25 juin 2010
 * Time: 19:16:50
 * To change this template use File | Settings | File Templates.
 */
public class CodeServiceImpl implements CodeService{
    private Cache codeCache;

    public CodeServiceImpl(){

        Map props = new HashMap();
        props.put(GCacheFactory.EXPIRATION_DELTA, 3600);

        try {
            CacheFactory cacheFactory = CacheManager.getInstance().getCacheFactory();
            codeCache = cacheFactory.createCache(props);
            codeCache = cacheFactory.createCache(Collections.emptyMap());
            
        } catch (CacheException e) {

        }
    }

    public Code getCode(Session session) throws CodeNotFoundException {
        return getCodeById(getCodeId());
    }

    public Code insertCode(byte[] code) {
        PersistenceManager pm = PMF.get().getPersistenceManager();
        ScriptContainer sc = new ScriptContainer(code);
        sc = pm.makePersistent(sc);
        return new CodeImpl(sc.getScript(),sc.getId().toString());
    }

    public Code getCodeById(Long codeId) throws CodeNotFoundException {
        Code code = (Code) codeCache.get(codeId);
        if(code==null){
            code = getUncachedCode(codeId);
            codeCache.put(codeId,code);
        }
        return code;
    }

    private Code getUncachedCode(Long codeId) throws CodeNotFoundException {
        PersistenceManager pm = PMF.get().getPersistenceManager();
        try {
            Key key = KeyFactory.createKey(ScriptContainer.class.getSimpleName(), codeId);
            ScriptContainer sc = pm.getObjectById( ScriptContainer.class, key);
            if(sc==null) throw new CodeNotFoundException("The code with id " + codeId + " not found.");
            return new CodeImpl(sc.getScript(),sc.getId().toString());
        } finally {
            pm.close();
        }
    }

    //Random codeId selection
    private Long getCodeId() throws CodeNotFoundException {
        PersistenceManager pm = PMF.get().getPersistenceManager();
        Query query = pm.newQuery(ScriptContainer.class);
        query.setOrdering("id desc");

        Query q = pm.newQuery("select id from " + ScriptContainer.class.getName());
        List ids = (List) q.execute();
        if(ids.size()==0) throw new CodeNotFoundException("There are no codes available");
        int i = ((int) Math.rint(System.currentTimeMillis()) * ids.size());
        return (Long)ids.get(i);
    }

}
